# -*- coding:utf-8 -*-
from bson import ObjectId

from ioservice.common.mongo import find_one_doc, insert_one_model, insert_models, find_many_models, \
    fake_delete_models_by_ids, \
    count_documents as mongo_count_docs, fake_delete_models, update_docs, update_one_doc, bulk_update_models_through_id, \
    bulk_update_models_unset_fields_though_id
from ioservice.const import *
from models.alumni import *
from models.alumni_extra import AlumniExtraDataSearchModel, AlumniExtraDataType, AlumniExtraDataModel


async def insert_reward(reward: AlumniExtraDataModel):
    """
    创建成果
    """
    reward.trans_data_model()
    reward_col = reward.set_data_col()
    _id = await insert_one_model(reward_col, reward.data)
    return str(_id)


async def bulk_insert_rewards(reward_col, reward_model: BaseModel, rewards: List[dict]):
    """
    批量创建成果
    """
    reward_models = [reward_model(**reward) for reward in rewards]
    res = await insert_models(reward_col, reward_models)

    return [str(_id) for _id in res]


async def get_reward_by_query(reward_col, reward_model, query, **kwargs):
    """
    根据搜索语句获取成果
    """
    rewards = await find_many_models(reward_col, reward_model, query, sort=kwargs.get("sort", ["-id"]),
                                     offset=kwargs.get("offset", 0), size=kwargs.get("size", 20),
                                     fields=kwargs.get("fields", None))
    return rewards


async def get_reward_by_context(context: AlumniExtraDataSearchModel):
    """
    根据搜索条件获取成果
    """
    if not context.check_info_type(data_type=AlumniExtraDataType.reward):
        raise InvalidParam("Operating Exception", f"{str(context.data_model)} not in alumni reward")
    reward_col, reward_model, reward_query = context.compose_mongo_query()
    total = await mongo_count_docs(reward_col, reward_query)
    result = await get_reward_by_query(reward_col, reward_model, reward_query, sort=context.parameters.sort,
                                       offset=context.parameters.offset,
                                       size=context.parameters.size, fields=context.parameters.fields)
    return total, result


async def get_reward_by_alumni_id(alumni_id, context: AlumniExtraDataSearchModel):
    """
    根据校友id和搜索条件获取成果
    """
    reward_col, reward_model, reward_query = context.compose_mongo_query()
    reward_query.update({"person_ids": ObjectId(alumni_id), "is_deleted": {"$ne": True}})
    total = await mongo_count_docs(reward_model, reward_query)
    res = await get_reward_by_query(reward_col, reward_model, reward_query, sort=context.parameters.sort,
                                    offset=context.parameters.offset,
                                    size=context.parameters.size, fields=context.parameters.fields)
    return {"total": total, "data": res}


async def update_rewards_by_query(reward_col, search_query, update_query):
    """
    通过语句批量更新成果
    """
    return await update_docs(reward_col, search_query, update_query)


async def bulk_update_rewards(reward_col, reward_model, rewards: List[dict]):
    update_rewards = []
    for doc in rewards:
        if not doc.get("id"):
            raise InvalidParam("reward_id", "reward id not exists")
        update_rewards.append(reward_model(**doc))
    if len(update_rewards) == 1:
        res = await bulk_update_models_through_id(reward_col, update_rewards)
    else:
        res = await bulk_update_models_unset_fields_though_id(reward_col, update_rewards, reward_model)
    return res


async def drop_rewards_by_query(reward_col, reward_query):
    """
    根据语句删除对应成果
    """
    res = await fake_delete_models(reward_col, reward_query)
    return res


async def drop_rewards_by_reward_ids(reward_col, reward_ids):
    """
    根据成果id删除对应成果
    """
    if not reward_ids:
        return 0
    res = await fake_delete_models_by_ids(reward_col, reward_ids)
    return res


async def add_alumni_to_rewards(reward_col: str, alumni_ids: List[OID], reward_ids: List[OID]):
    """
    在成果中添加校友
    """
    search_query = {"_id": {"$in": reward_ids}}
    update_query = {"$addToSet": {"person_ids": {"$each": alumni_ids}}}
    res = await update_docs(reward_col, search_query, update_query)
    return res


async def drop_alumni_from_rewards(reward_col, alumni_ids: List[OID], reward_ids: List[OID], drop_all=False):
    """
    在成果中删除校友
    """
    if not reward_ids and drop_all:
        search_query = {"person_ids": {"$in": alumni_ids}}
    else:
        search_query = {"_id": {"$in": reward_ids}}
    update_query = {"$pullAll": {"person_ids": alumni_ids}}
    res = await update_docs(reward_col, search_query, update_query)
    return res


async def insert_reward_with_alumni(alumni_id: OID, data_model: AlumniExtraDataModel):
    # TODO 暂时不可用
    data_model.set_data_col()
    alumni = await find_one_doc(alumni_col, {"_id": ObjectId(alumni_id)}, projection=["_id", "person_id"])
    if not alumni:
        raise InvalidParam("alumni", f"{alumni_id} does not exists")
    reward_id = await insert_reward(data_model)
    await update_one_doc(data_model.data_col, {"_id": ObjectId(reward_id)}, {"addToSet": {"person_ids": alumni_id}})
